# ChopFacilitate config file for perl.

use File::Temp qw/mkdtemp/;

$WGET = "/usr/bin/wget";

$PROBLEMS_DIR = "$HOME_DIR/problems";
$WORK_DIR = "$HOME_DIR/work";
$NODE_STATUS_DIR = "$HOME_DIR/nodeStatuses";
$DESTROYED_NODES_FILE = "$HOME_DIR/destroyedNodes";
$ALLNODES_FILE = "$HOME_DIR/allNodes";

sub killJob{
	my($targetJobID, $nodeName) = @_;
	my($uri) = &node2uri($nodeName);
	if($uri ne ''){
		`$WGET -q -O - --post-data=${targetJobID}_${nodeName} $uri/kill.cgi`;
	}
}
sub killAllJobOnNode{
	my($node) = @_;
	my($uri) = &node2uri($node);
	if($uri ne ''){
		`$WGET -q -O - --post-data=all $uri/kill.cgi`;
	}
}

sub destroyNodes{
	my(@nodes) = @_;
	my($out, $line);
	if(!(-f "$DESTROYED_NODES_FILE")){
		close(NODE) if(open(NODE, ">>$DESTROYED_NODES_FILE"));
	}
	open(NODE, "+<$DESTROYED_NODES_FILE") || return 0;
	flock(NODE, 2);
	seek(NODE, 0, 0);
	my($targetNodes) = " @nodes ";
	while($line = <NODE>){
		s/\r?\n$//;
		my($n) = $_;
		next if($n =~ m/^$/);
		next if($targetNodes =~ m/ $n /);
		$out .= $line;
	}
	$out .= join("\n", @nodes). "\n";
	seek(NODE, 0, 0);
	truncate(NODE, length($out));
	print NODE $out;
	flock(NODE, 8);
	close(NODE);
	my($node);
	foreach $node (@nodes){
		my($uri) = &node2uri($node);
		next if($uri eq '');
		next unless(open(JOB, "+<$NODE_STATUS_DIR/$node"));
		flock(JOB, 1);
		seek(JOB, 0, 0);
		while(<JOB>){
			s/\r?\n$//;
			`$WGET -q -O /dev/null --post-data='${_}_$node' $uri/kill.cgi`;
		}
		flock(JOB, 8);
		close(JOB);
		unlink("$NODE_STATUS_DIR/$node");
	}
}

sub cameBackNodes{
	my(@nodes) = @_;
	my($out, $line);
	if(!(-f "$DESTROYED_NODES_FILE")){
		close(NODE) if(open(NODE, ">>$DESTROYED_NODES_FILE"));
	}
	open(NODE, "+<$DESTROYED_NODES_FILE") || return 0;
	flock(NODE, 2);
	seek(NODE, 0, 0);
	my($targetNodes) = " @nodes ";
	while($line = <NODE>){
		s/\r?\n$//;
		my($n) = $_;
		next if($n =~ m/^$/);
		next if($targetNodes =~ m/ $n /);
		$out .= $line;
	}
	seek(NODE, 0, 0);
	truncate(NODE, length($out));
	print NODE $out;
	flock(NODE, 8);
	close(NODE);
}

sub deleteNodeJob{
	my($node, $job) = @_;
	my($out, $line);
	open(JOB, "+<$NODE_STATUS_DIR/$node") || return 0;
	flock(JOB, 2);
	seek(JOB, 0, 0);
	while($line = <JOB>){
		next if($line =~ m/^$job\r?\n$/);
		$out .= $line;
	}
	seek(JOB, 0, 0);
	truncate(JOB, length($out));
	print JOB $out;
	flock(JOB, 8);
	close(JOB);
}

sub addNodeJob{
	my($node, $job) = @_;
	my($out, $line);
	if(!(-f "$NODE_STATUS_DIR/$node")){
		close(JOB) if(open(JOB, ">>$NODE_STATUS_DIR/$node"));
	}
	open(JOB, "+<$NODE_STATUS_DIR/$node") || return 0;
	flock(JOB, 2);
	seek(JOB, 0, 0);
	while($line = <JOB>){
		if($line =~ m/^$job\r?\n$/){
			flock(JOB, 8);
			close(JOB);
			return 0;
		}
		$out .= $line;
	}
	$out .= "$job\n";
	seek(JOB, 0, 0);
	print JOB $out;
	flock(JOB, 8);
	close(JOB);
}

sub getJobResults{
	my($jobdir, $resultFile, %result);
	if(opendir(DIR, $WORK_DIR)){
		while(defined($jobdir = readdir(DIR))){
			next if($jobdir =~ m/^\./);
			$resultFile = "$WORK_DIR/$jobdir/result";
			my($job) = $jobdir;
			$job =~ s|.*/||;
			if(open(RESULT, "<$resultFile")){
				$result{$job} = join('', <RESULT>);
				close(RESULT);
			}else{
				$result{$job} = "not solved";
			}
		}
		return %result;
	}
	return undef;
}

sub listDestroyedNodes{
	my(@nodes) = @_;
	my(@result);
	open(FILE, "<$DESTROYED_NODES_FILE") || return undef;
	flock(FILE, 1);
	seek(FILE, 0, 0);
	my($line, $i);
	while($line = <FILE>){
		$line =~ s/\r?\n$//;
		for($i = 0; $i <= $#nodes; $i++){
			if($nodes[$i] eq $line){
				push(@result, $line);
				last;
			}
		}
	}
	flock(FILE, 8);
	close(FILE);
	return @result;
}
sub cropAliveNodes{
	my(@nodes) = @_;
	my($line, $i);
	open(FILE, "<$ALLNODES_FILE") || return @nodes;
	my(@result);
	while($line = <FILE>){
		my($node, $url) = ($line =~ m/^([^\s]+)\s+(.*)\r?\n$/);
		for($i = 0; $i <= $#nodes; $i++){
			if($nodes[$i] eq $node){
				push(@result, $node);
				last;
			}
		}
	}
	@nodes = @result;
	close(FILE);
	open(FILE, "<$DESTROYED_NODES_FILE") || return @nodes;
	flock(FILE, 1);
	seek(FILE, 0, 0);
	while($line = <FILE>){
		$line =~ s/\r?\n$//;
		for($i = 0; $i <= $#nodes; $i++){
			if($nodes[$i] eq $line){
				splice(@nodes, $i, 1);
				last;
			}
		}
	}
	flock(FILE, 8);
	close(FILE);
	return @nodes;
}

sub isNotNodeDestoryed{
	my($node) = @_;
	open(FILE, "<$DESTROYED_NODES_FILE") || return 1;
	flock(FILE, 1);
	seek(FILE, 0, 0);
	while(<FILE>){
		if(m/^$node\r?\n?$/){
			close(FILE);
			return 0;
		}
	}
	flock(FILE, 8);
	close(FILE);
	return 1;
}
# node name to url converter
sub node2uri{
	my($node) = @_;
	if(defined(%ChopSetTemp::NodeList)){
		my($uri) = $ChopSetTemp::NodeList{$node};
		return $uri if($uri ne '');
	}
	open(FILE, "<$ALLNODES_FILE") || return undef;
	while(<FILE>){
		s/\r?\n$//;
		my($name, $url) = split(/\s+/, $_, 2);
		$ChopSetTemp::NodeList{$name} = $url;
	}
	close(FILE);
	return $ChopSetTemp::NodeList{$node};
}

{
	package ChopSetTemp;
	# for cache
}

sub getNodeList{
	open(FILE, "<$ALLNODES_FILE") || return undef;
	my(@nodes);
	while(<FILE>){
		my($node, $url) = split(/\s+/, $_, 2);
		push(@nodes, $node);
	}
	close(FILE);
	return @nodes;
}

# return value are hash.
# key: nodename
# value: status
sub getStatus{
	my($status_dir) = $NODE_STATUS_DIR;
	my(%status);

	if(!(-d $status_dir)){
		return %status;
	}

	# node status files contained in  $NODE_STATUS_DIR
	# status file name is node name
	# status file contained node status string
	opendir(DIR, $status_dir) || return ();
	my($file);
	while(defined($file = readdir(DIR))){
		next if($file =~ m/^\./);
		if(open(FILE, "$status_dir/$file")){
			my($status) = <FILE>;
			$status =~ s/\r?\n$//;
			$status{$file} = $status if($status ne '');
			close(FILE);
		}
	}
	closedir(DIR);

	return %status;
};

# return value is created directory name.
sub createWorkingDirectory {
	my($hint) = @_;
	my($time) = scalar(localtime());
	$time =~ s/\s+/_/g;
	return mkdtemp("$WORK_DIR/${hint}_${time}_XXXX");
};

sub daemon{
	close(STDIN); close(STDOUT); close(STDERR);
        open STDIN, "/dev/null";
        open STDOUT, ">>/dev/null";
	#open STDOUT, ">>stdout_log";
	open STDERR, ">>/dev/null";

	if($pid = fork()){
		exit(0);
	}elsif(defined($pid)){
		setsid;
		return 1;
	}else{
		# filed.
		return 0;
	}
	return 0;
}

1;
